package server.session;

import server.Context;
import server.Manager;
import server.Session;
import server.util.Enumerator;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class StandardSession implements HttpSession, Session, Serializable {
    //不完整的方法-----------------------------------------------------------------------
    @Override
    public void setAttribute(String name, Object value) {
        if (name == null)
            throw new IllegalArgumentException("name不能为null");
        if (value == null) {
            removeAttribute(name);
            return;
        }
        if (!isValid)
            throw new IllegalStateException("Session失效");
//        if ((manager != null) && manager.getDistributable() &&
//                !(value instanceof Serializable))
//            throw new IllegalArgumentException("xxx");
        synchronized (attributes) {
            attributes.put(name, value);
        }

    }
    //-----------------------------------------------------------------------
    private static HttpSessionContext sessionContext = null;
    private static final String info = "StandardSession/1.0";
    private Manager manager = null;
    private transient int debug = 0;
    //存放属性
    private Map<String, Object> attributes = new HashMap<>();

    private String id = null;
    private boolean isNew = false;
    private boolean isValid = false;
    //创建Session的时间
    private long creationTime = 0L;
    //最后一次访问Session的时间
    private long lastAccessedTime = creationTime;
    private long thisAccessedTime = creationTime;
    //客户端离上一次请求的时间大于maxInactiveInterval秒时,该Session失效。为负数不会失效
    private int maxInactiveInterval = -1;

    private transient StandardSessionFacade facade = null;

    public StandardSession(Manager manager) {
        this.manager = manager;
        if (manager instanceof ManagerBase)
            this.debug = ((ManagerBase)manager).getDebug();
    }

    private void log(String message, Throwable throwable) {
        if (manager != null && manager instanceof ManagerBase) {
            ((ManagerBase) manager).log(message, throwable);
        } else {
            System.out.println("StandardSession: " + message);
            throwable.printStackTrace(System.out);
        }
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("StandardSession[");
        sb.append(id);
        sb.append("]");
        return (sb.toString());
    }

    //实现HttpSession接口-------------------------------------------------------------------------
    @Override
    public long getCreationTime() {
        if (!isValid)
            throw new IllegalStateException("Session失效");
        return this.creationTime;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public long getLastAccessedTime() {
        return this.lastAccessedTime;
    }

    @Override
    public ServletContext getServletContext() {
        if (manager == null)
            return null;
        Context context = (Context)(manager.getContainer());
        if (context != null)
            return context.getServletContext();
        return null;
    }

    @Override
    public void setMaxInactiveInterval(int interval) {
        this.maxInactiveInterval = interval;
    }

    @Override
    public int getMaxInactiveInterval() {
        return this.maxInactiveInterval;
    }

    @Override
    public HttpSessionContext getSessionContext() {
        if (sessionContext == null)
            sessionContext = new StandardSessionContext();
        return sessionContext;
    }

    @Override
    public Object getAttribute(String name) {
        if (!isValid)
            throw new IllegalStateException("Session失效");
        synchronized (attributes) {
            return attributes.get(name);
        }
    }

    @Override
    public Object getValue(String name) {
        return getAttribute(name);
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        if (!isValid)
            throw new IllegalStateException("Session失效");
        synchronized (attributes) {
            return new Enumerator<String>(attributes.keySet());
        }
    }

    @Override
    public String[] getValueNames() {
        if (!isValid)
            throw new IllegalStateException("Session失效");
        synchronized (attributes) {
            String[] names = new String[attributes.size()];
            return attributes.keySet().toArray(names);
        }
    }

    @Override
    public void putValue(String name, Object value) {
        setAttribute(name, value);
    }

    @Override
    public void removeAttribute(String name) {
        if (/*!expiring && */ !isValid)
            throw new IllegalStateException("Session失效");
        synchronized (attributes) {
            attributes.remove(name);
        }
    }

    @Override
    public void removeValue(String name) {
        removeAttribute(name);
    }

    //使Session失效
    @Override
    public void invalidate() {
        if (!isValid)
            throw new IllegalStateException("Session已经失效");
        if (manager != null)
            manager.remove(this);
        //触发session销毁事件
        Context context = (Context)(manager.getContainer());
        Object[] listeners = context.getApplicationListeners();
        if (listeners == null)
            return;
        HttpSessionEvent event = new HttpSessionEvent(getSession());
        for (int i = listeners.length - 1; i >= 0 ; i--) {
            if (!(listeners[i] instanceof HttpSessionListener))
                continue;
            HttpSessionListener sessionListener = (HttpSessionListener)listeners[i];
            try {
                sessionListener.sessionDestroyed(event);
            } catch (Throwable t) {
                log("监听session销毁时间的监听器执行错误", t);
            }
        }
    }


    @Override
    public boolean isNew() {
        return this.isNew;
    }


    //实现Session接口-------------------------------------------------------------------------


    @Override
    public boolean isValid() {
        return isValid;
    }

    @Override
    public void setValid(boolean isValid) {
        this.isValid = isValid;
    }

    @Override
    public void setNew(boolean isNew) {
        this.isNew = isNew;
    }

    @Override
    public void setCreationTime(long creationTime) {
        this.creationTime = creationTime;
        this.lastAccessedTime = creationTime;
        this.thisAccessedTime = creationTime;
    }

    //设置SessionId 会触发Session的监听器
    @Override
    public void setId(String id) {
        if (this.id != null && manager != null)
            manager.remove(this);
        this.id = id;
        if (manager != null)
            manager.add(this);

        Context context = (Context)(manager.getContainer());
        Object[] listeners = context.getApplicationListeners();
        if (listeners == null)
            return;
        HttpSessionEvent event = new HttpSessionEvent(getSession());
        for (Object listener : listeners) {
            if (!(listener instanceof HttpSessionListener))
                continue;
            HttpSessionListener sessionListener = (HttpSessionListener)listener;
            try {
                sessionListener.sessionCreated(event);
            } catch (Throwable t) {
                log("监听session创建的监听器执行出错", t);
            }
        }
    }


    @Override
    public HttpSession getSession() {
        if (facade == null)
            facade = new StandardSessionFacade(this);
        return facade;
    }

    //StandardSessionContext类-----------------------------------------------------
    final class StandardSessionContext implements HttpSessionContext {
        private Map<String, String> dummy = new HashMap<>();
        @Override
        public HttpSession getSession(String id) {
            return null;
        }

        @Override
        public Enumeration<String> getIds() {
            return new Enumerator<String>(dummy.values().iterator());
        }
    }
}


